package postpc.powerreminders.com.location;

import java.util.List;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Handler;
import android.util.Log;

public class MovmentDetector implements SensorEventListener{

	/*
	 * The shake threshold that indicates movement 
	 */
	private static final int SHAKE_THRESHOLD = 150;
	
	/*
	 * Logger tag
	 */
	private static final String TAG = "ROTG_SENSORS";

	/*
	 * Reference to the location manager.
	 */
	private RotgLocationManager locationManager;

	/*
	 * Reference to the sensor manager for sensor services.
	 */
	SensorManager sensorMgr;

	/*
	 * Reference to the power manager.
	 */
	RotgPowerManager powerManager;

	/*
	 * Handle to the ACCELEROMETER
	 */
	Sensor sensor;

	/*
	 * Handler for a delayed task.
	 */
	Handler handler = new Handler();

	/*
	 * Sensor fields for power management
	 */
	private long lastUpdate = -1;
	private float x, y, z;
	private float last_x, last_y, last_z;

	// Minimum number of MS before updates
	private static final long MIN_TIME_FOR_UPDATE = 100;
	private static final long DEFAULT_SENSOR_SLEEP_TIME = 3000;
	protected static final long DEFAULT_SENSOR_WAKE_TIME = 1000;

	/**
	 * Motion detector sensor.
	 * Used to detect movement in order to turn on WiFi and GPS scans.
	 * 
	 * @param ma
	 * @param pm
	 * @param em
	 */
	public MovmentDetector (RotgLocationManager lm, 
			RotgPowerManager pm){

		Log.i(TAG, "Starting Sensor creation");

		this.powerManager = pm;

		this.locationManager = lm;

		// Get Sensors
		this.sensorMgr = (SensorManager) this.locationManager.context.getSystemService(Context.SENSOR_SERVICE);
		List<Sensor> sensors = this.sensorMgr.getSensorList(Sensor.TYPE_ACCELEROMETER);

		// No accelerometer
		if (sensors.size() == 0){
			Log.e(TAG, "No sensors found");
			this.locationManager.notifyUserDialog("NO ACCELEROMETER, Good Power managment not supported");
			sensorMgr.unregisterListener(this,sensor);
			sensorMgr = null;
			return;
		}

		// Save handle to the sensor.
		Log.i(TAG, "Got Sensor");
		this.sensor = sensors.get(0);

		handler.postDelayed(updateTimeTask, DEFAULT_SENSOR_SLEEP_TIME);
	}

	/**
	 * On accuracy changes
	 */
	@Override
	public void onAccuracyChanged(Sensor arg0, int arg1) {
		Log.i(TAG, "Got accuracy change");
	}

	/**
	 * 
	 */
	@Override
	public void onSensorChanged(SensorEvent sensorEvent) {

		long curTime = System.currentTimeMillis();
		Log.i(TAG, "Sensor chnage, time:" + curTime);

		// only allow one update every 100ms.
		if ((curTime - lastUpdate) > MIN_TIME_FOR_UPDATE) {
			long diffTime = (curTime - lastUpdate);
			lastUpdate = curTime;

			// Get values
			x = sensorEvent.values[SensorManager.DATA_X];
			y = sensorEvent.values[SensorManager.DATA_Y];
			z = sensorEvent.values[SensorManager.DATA_Z];

			float speed = Math.abs(x + y + z - last_x - last_y - last_z) / diffTime * 10000;
			Log.i(TAG, "Sensor detected speed: " + speed);
			if (speed > SHAKE_THRESHOLD) {
				Log.i(TAG, "NOTIFY MOVMENT");
				this.locationManager.notifyMovment();
			}

			last_x = x;
			last_y = y;
			last_z = z;
		}
	}

	/**
	 * Gets the listener handle.
	 * 
	 * @return
	 */
	protected MovmentDetector getMovmentSensorListener(){
		return this;
	}

	/**
	 * Task Handler for the Sensor differed task. 
	 */
	public Runnable updateTimeTask = new Runnable() {
		boolean working = false;

		public void run() {
			if (working){
				Log.i(TAG, "Sensor working");
				sensorMgr.unregisterListener(getMovmentSensorListener(),sensor);
				handler.postDelayed(updateTimeTask, DEFAULT_SENSOR_SLEEP_TIME);
				working = false;
			} else {
				Log.i(TAG, "Sensor not working"); 
				handler.postDelayed(updateTimeTask, DEFAULT_SENSOR_WAKE_TIME);
				sensorMgr.registerListener(getMovmentSensorListener(), sensor, SensorManager.SENSOR_DELAY_NORMAL);
				working = true;
			}
		}
	};

	/*
	 * Called on application shutdown
	 */
	public void shutdown(){
		Log.i(TAG, "Shuting down sensor");
		handler.removeCallbacks(updateTimeTask);
		try {
			sensorMgr.unregisterListener(this,sensor);
		} catch (Exception e){
			Log.i(TAG, "No listener registered");
		}
	}
}